﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;

namespace UC_Framework
{

    /// <summary>
    /// A list of sprites with some basic management functions
    /// </summary>
    public class SpriteList : UC_Renderable
    {
        Sprite2[] sprite;
        int numOfSprites;

        /// <summary>
        /// Lowest free sprite num (for use in external loops rarely needed)
        /// </summary>
        public int lowFree = 0; // lowest free sprite
        /// <summary>
        /// Highest free sprite num (for use in external loops rarely needed)
        /// </summary>
        public int highUsed = 0; // highest used
        int counter = 0;

        /// <summary>
        /// Constructor for spritelist
        /// </summary>
        public SpriteList()
        {
        initialise(200);
        }

        /// <summary>
        /// Constructor if you want to manage how many sprites
        /// </summary>
        /// <param name="NumOfSprites"></param>
        public SpriteList(int NumOfSprites)
        {
            initialise(NumOfSprites);
        }

        private void initialise(int NumOfSprites)
        {
            numOfSprites = NumOfSprites;
            sprite = new Sprite2[numOfSprites];
            for (int i = 0; i < numOfSprites; i++)
            {
                sprite[i] = null;
            }
        }

        /// <summary>
        /// counts sprites in list (active, inactive , visible, not visible) fairly useless
        /// </summary>
        /// <returns></returns>
        public int count()
        {
            counter = 0;
            for (int i = 0; i < numOfSprites; i++)
            {
                if (sprite[i] != null) counter++;
            }
            return counter;
        }

        /// <summary>
        /// Get max number of sprites in this list
        /// </summary>
        /// <returns></returns>
        public int getMaxNumOfSprites()
        {
            return numOfSprites;
        }

        /// <summary>
        /// get the index of the highest used sprite 
        /// </summary>
        /// <returns></returns>
        /// 
        // example of use  
        // <code> "for (int i = 0; i <mysprite.getHighestUsed()+1; i++)" </code>
        // dont forget to check for null (and visible or active if needed)
        public int getHighestUsed()
        {
            return highUsed;
        }

        /// <summary>
        /// Finds a free slot in the sprite list or -1 if it fails 
        /// </summary>
        /// <returns></returns>
        public int findFreeSprite()
        {
            for (int i = 0; i < numOfSprites; i++)
            {
                if (sprite[i] == null) return i;
            }
            return -1;
        }

        /// <summary>
        /// Finds a free slot in the sprite list or an inactive sprite -1 if it fails 
        /// </summary>
        /// <returns></returns>
        public int findFreeSpriteOrInactive()
        {
            for (int i = 0; i < numOfSprites; i++)
            {
                if (sprite[i] == null) return i;
                if (sprite[i].active == false) return i; 
            }
            return -1;
        }

        /// <summary>
        /// Add a sprite and return then number we added it at
        /// </summary>
        /// <param name="spriteZ"></param>
        /// <returns></returns>
        public int addSprite(Sprite2 spriteZ)
        {
            int i = findFreeSprite();
            if (i != -1)
            {
                setSprite(i, spriteZ);
                if (i > highUsed) highUsed = i;
                return i;
            }
            return -1;
        }

        /// <summary>
        /// Add a sprite and return then number we added it at and allow inactive sprites to be oever written
        /// </summary>
        /// <param name="spriteZ"></param>
        /// <returns></returns>
        public int addSpriteReuse(Sprite2 spriteZ)
        {
            int i = findFreeSpriteOrInactive();
            if (i != -1)
            {
                setSprite(i, spriteZ);
                if (i > highUsed) highUsed = i;
                return i;
            }
            return -1;
        }

        

        /// <summary>
        /// return the particular sprite
        /// </summary>
        /// <param name="i"></param>
        /// <returns></returns>
        public Sprite2 getSprite(int i)
        {
            return sprite[i];
        }

        /// <summary>
        /// Remove a sprite 
        /// </summary>
        /// <param name="i"></param>
        public void deleteSprite(int i)
        {
            setSprite(i, null);
        }

        /// <summary>
        /// Replace or set a specifically numbered sprite
        /// </summary>
        /// <param name="i"></param>
        /// <param name="spriteZ"></param>
        public void setSprite(int i, Sprite2 spriteZ)
        {
            sprite[i] = spriteZ;
            if (spriteZ == null && i < lowFree) lowFree = i; 
            if (spriteZ != null && i > highUsed) highUsed = i;
        }

        /// <summary>
        /// draw all visible sprites
        /// </summary>
        /// <param name="sb"></param>
        public override void Draw(SpriteBatch sb)
        {
            drawActive(sb);
        }

        /// <summary>
        /// draw all visible sprites
        /// </summary>
        /// <param name="sb"></param>
        public void drawAll(SpriteBatch sb)
        {
            for (int i = 0; i < highUsed+1; i++)
            {
                if (sprite[i] != null) 
                    if (sprite[i].getVisible())
                        sprite[i].draw(sb);
            }
        }

        /// <summary>
        /// Animatin tick all visible sprites
        /// </summary>
        public void animationTick()
        {
            for (int i = 0; i < highUsed + 1; i++)
            {
                if (sprite[i] != null)
                    if (sprite[i].getVisible())
                        sprite[i].animationTick();
            }
        }

        /// <summary>
        /// Run routine tick on all sprites - this may alter their visiblity staus
        /// </summary>
        public void Tick()
        {
            for (int i = 0; i < highUsed + 1; i++)
            {
                if (sprite[i] != null)
                    sprite[i].tick();
            }
        }

        /// <summary>
        /// Run routine tick on all sprites - this may alter their visiblity staus
        /// </summary>
        public override void Update(GameTime gameTime)
        {
            for (int i = 0; i < highUsed + 1; i++)
            {
                if (sprite[i] != null)
                    sprite[i].Update(gameTime);
            }
        }

        

        /// <summary>
        /// Draw all active sprites
        /// </summary>
        /// <param name="sb"></param>
        public void drawActive(SpriteBatch sb)
        {
            for (int i = 0; i < highUsed + 1; i++)
            {
                if (sprite[i] != null)
                    if (sprite[i].getVisible() && sprite[i].active)
                        sprite[i].draw(sb);
            }
        }

        /// <summary>
        /// Move active by angle/dist
        /// </summary>
        /// <param name="fullMove"></param>
        public void moveActiveAD(bool fullMove)
        {
            for (int i = 0; i < highUsed + 1; i++)
            {
                if (sprite[i] != null)
                    if (sprite[i].active)
                        sprite[i].moveByAngleSpeed(fullMove);
            }
        }

        /// <summary>
        /// Removes (makes inactive) all sprites whos bouding vbox is outside r 
        /// </summary>
        /// <param name="r"></param>
        public void removeIfOutside(Rectangle r)
        {
            for (int i = 0; i < highUsed + 1; i++)
            {
                if (sprite[i] != null)
                    if (sprite[i].active)
                    {
                     if (!r.Intersects(sprite[i].getBoundingBoxAA()))
                        {
                            sprite[i].active = false;
                            sprite[i].visible = false;
                        }
                    }
            }
        }

        /// <summary>
        /// Move visible or active by delat x delta y
        /// </summary>
        /// <param name="fullMove"></param>
        public void moveDeltaXY_VA(bool fullMove)
        {
            for (int i = 0; i < highUsed + 1; i++)
            {
                if (sprite[i] != null)
                    if (sprite[i].active || sprite[i].getVisible())
                        sprite[i].moveByDeltaXY(fullMove);
            }
        }

        /// <summary>
        /// Move active by delta x delta y
        /// </summary>
        /// <param name="fullMove"></param>
        public void moveDeltaXY_A(bool fullMove)
        {
            for (int i = 0; i < highUsed + 1; i++)
            {
                if (sprite[i] != null)
                    if (sprite[i].active)
                    {
                        sprite[i].moveByDeltaXY(fullMove);
                    }
            }
        }

        /// <summary>
        /// Move all visible sprites by their waypoint
        /// </summary>
        /// <param name="fullMove"></param>
        public void moveVisibleWayPoints(bool fullMove)
        {
            for (int i = 0; i < highUsed + 1; i++)
            {
                if (sprite[i] != null)
                    if (sprite[i].getVisible())
                        sprite[i].moveWayPointList(fullMove, false);
            }
        }


        /// <summary>
        /// Draw BB and hotspot for all visible sprites 
        /// </summary>
        /// <param name="sb"></param>
        /// <param name="colorBB"></param>
        /// <param name="colorHS"></param>
        public void drawInfo(SpriteBatch sb, Color colorBB, Color colorHS)
        {
            for (int i = 0; i < highUsed + 1; i++)
            {
                if (sprite[i] != null)
                    if (sprite[i].getVisible() ) sprite[i].drawInfo(sb, colorBB, colorHS);
            }
        }

        /// <summary>
        /// Draw the waypoints
        /// </summary>
        /// <param name="sb"></param>
        /// <param name="colorW"></param>
        public void drawWayLists(SpriteBatch sb, Color colorW)
        {
            for (int i = 0; i < highUsed + 1; i++)
            {
                if (sprite[i] != null)
                    if (sprite[i].getVisible()) 
                        if (sprite[i].wayList != null) sprite[i].wayList.Draw(sb, colorW, colorW);
            }
        }


        /// <summary>
        /// draws the rotated bounding box for all visible sprites
        /// </summary>
        /// <param name="sb"></param>
        /// <param name="color"></param>
        public void drawRect4(SpriteBatch sb, Color color)
        {
            for (int i = 0; i < highUsed + 1; i++)
            {
                if (sprite[i] != null)
                    if (sprite[i].getVisible())
                    {
                        sprite[i].getBoundingBoxAA(); // to put values in 
                        sprite[i].drawRect4(sb, color);
                    }
            }
        }

        /// <summary>
        /// Returns the index of the first (ie lowest numbered) 
        /// sprite it colides with
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        public int collisionAA(Sprite2 s)
        {
        return collisionAA(s,-1);
        }

        /// <summary>
        /// Returns the index of the first (ie lowest numbered) 
        /// sprite it colides with
        /// the self parameter is there to allow the avoidance of collision texting against yourself
        /// </summary>
        /// <param name="s">the sprite to test the list against</param>
        /// <param name="self">the number of a single sprite to avoid testing</param>
        /// <returns></returns>
        public int collisionAA(Sprite2 s, int self)
        {
            if (!s.getVisible()) return -1;
            for (int i = 0; i < highUsed + 1; i++)
            {
                if (sprite[i] != null)
                    if (sprite[i].getVisible() &&
                        i != self && s.collision(sprite[i]))
                    {
                        return i;
                    }      
            }
            return -1;
        }

        /// <summary>
        /// Returns the index of the first (ie lowest numbered) 
        /// sprite it colides with
        /// the self parameter is there to allow the avoidance of collision texting against yourself 
        /// </summary>
        /// <param name="s"></param>
        /// <param name="self"></param>
        /// <returns></returns>
        public int collisionAANewPos(Sprite2 s, int self)
        {
            for (int i = 0; i < highUsed + 1; i++)
            {
                if (sprite[i] != null)
                    if (sprite[i].getVisible() && 
                        i != self && s.collisionNewPos(sprite[i]))
                    {
                        return i;
                    }
            }
            return -1;
        }

        /// <summary>
        /// returns  index of the first visible sprite that collides with r
        /// if no colission it returns -1 
        /// </summary>
        /// <param name="r"></param>
        /// <returns></returns>
        public int collisionWithRect(Rectangle r)
        {
            for (int i = 0; i < highUsed + 1; i++)
            {
                if (sprite[i] != null)
                    if (sprite[i].getVisible()) 
                        if (r.Intersects(sprite[i].getBoundingBoxAA()))
                        {
                        return i;
                        }
            }
            return -1;
        }


        /// <summary>
        /// Returns the number of the first sprite found 'under' the spot
        /// </summary>
        /// <param name="point"></param>
        /// <returns></returns>
        public int pointInList(Vector2 point)
        {
            for (int i = 0; i < highUsed + 1; i++)
            {
                if (sprite[i] != null)
                    if (sprite[i].getVisible() && sprite[i].inside(point.X, point.Y))
                    {
                        return i;
                    }
            }
            return -1;
        }

        /// <summary>
        /// Find inactive sprite or -1 if not found 
        /// </summary>
        /// <returns></returns>
        public int findInactive()
        {
            for (int i = 0; i < highUsed + 1; i++) if (sprite[i] != null)
            {
                if (!sprite[i].active) return i;
            }
            return -1;
        }

    }

    // ************************************************************************************************ //

    /// <summary>
    /// The UC_Framework Sprite2 Class
    /// This class has the concept that the position and hotspot are the same place
    /// and that this place is also the center of rotation, as a result all movement / rotation and collision routines 
    /// make use of this concept 
    /// </summary>
    public class Sprite2 : UC_Renderable
    {
        
        /// <summary>
        /// Just a version to help code controll
        /// </summary>
        public const string SpriteVersion ="V2.11";
        
        /// <summary>
        /// this variable called active is available for use by user code and is used to identify
        /// active sprires in a sprite list it defaults to true
        /// it is used in conjunction with sprite list to manage activity of sprites in a list
        /// </summary>
        //public bool active;

        /// <summary>
        /// is it visible
        /// </summary>
        public bool visible;

        /// <summary>
        /// this variable called kind is available for use by user code
        /// </summary>
        public int kind;   // not used by the framework, available for use by user code
        
        /// <summary>
        /// this variable called state is available for use by user code
        /// </summary>
        public int state;

        /// <summary>
        /// Used by user for id or text purposes
        /// </summary>
        public string name;

        /// <summary>
        /// this variable called tag is available for use by user code
        /// </summary>
        public float tag;

        /// <summary>
        /// this variable called score is available for use by user code
        /// </summary>
        public float score;

        /// <summary>
        /// this variable called hitPoints is available for use by user code
        /// </summary>
        public int hitPoints;

        /// <summary>
        /// variables called varInt0, varInt1, varInt2 are available for use by user code
        /// </summary>
        public int varInt0;
 
        /// <summary>
        /// available for use by user code
        /// </summary>
        public int varInt1;
        /// <summary>
        /// available for use by user code
        /// </summary>
        public int varInt2;
        /// <summary>
        /// available for use by user code
        /// </summary>
        public int varInt4;

        /// <summary>
        /// these variables called varBool0, varBool1 are available for use by user code
        /// </summary>
        public bool varBool0;
        /// <summary>
        /// available for use by user code
        /// </summary>
        public bool varBool1;

        /// <summary>
        /// this variable called target is available for use by user code
        /// </summary>
        public Vector2 target;
        
        /// <summary>
        /// The sprites texture2d 
        /// </summary>
        protected Texture2D tex;

        /// <summary>
        /// the direction of the sprite  
        /// </summary>
        protected SpriteEffects flip;

        /// <summary>
        /// the game level - by default it will be 0 
        /// </summary>
        protected int level;

        /// <summary>
        /// the sprites location 
        /// </summary>
        protected Vector2 pos; // the screen position now of top left/top right pixel
        
        /// <summary>
        /// the sprites proposed location after the next movement 
        /// </summary>
        protected Vector2 newPos; // the position proposed after the next move

        /// <summary>
        /// the previous position it is updated if the Sprite2 movement systems are used
        /// and can be used to compute a display angle
        /// this is for you to use/set if you have your own movement system 
        /// </summary>
        public Vector2 oldPos; 

        /// <summary>
        /// movement vector when using the deltax deltay movement system
        /// </summary>
        protected Vector2 deltaSpeed; // the X, y speed (delta x, delta Y)

        /// <summary>
        /// the movement angle in radians if using the angle / speed movement system
        /// </summary>
        protected float moveAngle;    // in radians

        /// <summary>
        /// the movement angle if using the angle / speed movement system
        /// </summary>
        protected float moveSpeed;

        /// <summary>
        /// the display angle in radians - which may or may not be the move angle
        /// </summary>
        protected float displayAngle; // in radians
        
        /// <summary>
        /// the display angle offset in radians 
        /// Added to display angle to make the sprite "point in direction 0"
        /// </summary>
        protected float displayAngleOffset; // in radians

        /// <summary>
        /// Partial source used if xframes = 0;
        /// </summary>
        protected Rectangle imageSource;

        /// <summary>
        /// Animation information - number of horizontal frames 
        /// </summary>
        protected int Xframes; // number of x frames 
        private int XframeWidth;

        /// <summary>
        ///  Animation information - number of vertical frames 
        /// </summary>
        protected int Yframes; // number of y frames
        private int YframeHeight;

        /// <summary>
        /// Animation information - current horizontal frame number
        /// frame numbers start at 0
        /// </summary>
        protected int Xframe; // number of the current x frame 

        /// <summary>
        /// Animation information - current vertical frame number
        /// frame numbers start at 0
        /// </summary>
        protected int Yframe; // number of the current y frame

        /// <summary>
        ///  The complete animation sequence that running now (if any)
        ///  this list contains x and y frame numbers and is itself indexed by frame
        /// </summary>
        protected Vector2[] animationSeq; // the frame sequence

        /// <summary>
        /// the frame withing sequence 'animationSeq'
        /// </summary>
        protected int frame; 
 
        /// <summary>
        ///  the first animation frame withing sequence 'animationSeq'
        /// </summary>
        protected int firstFrame; // first anim frame

        /// <summary>
        /// the last animation frame withing sequence 'animationSeq'
        /// </summary>
        protected int lastFrame;  // second anim frame

        /// <summary>
        /// A flag telling what to do when the animation finishes
        /// 0=loop
        /// 1=set sprite invisible
        /// 2=set sprite inactive and invisible
        /// </summary>
        protected int animFinished;

        /// <summary>
        /// number of ticks between aniamtion frames at 60 frames a second this could be as much as 20 or more
        /// </summary>
        protected int ticksBetweenFrames; // as it implies       
        
        /// <summary>
        /// just a counter as it implies for animation purposes
        /// </summary>
        protected int ticks; 

        /// <summary>
        /// The width of the sprite on the screen
        /// </summary>
        protected float width; 

        /// <summary>
        /// the height of the sprite on the screen in pixels
        /// </summary>
        protected float height; //
 
        /// <summary>
        /// the width of the meaningful part of the texture
        /// </summary>
        protected float texWidth; // Width of the useful part of the texture

        /// <summary>
        /// the height of the meaningful part of the texture
        /// </summary>
        protected float texHeight; // heigth of the useful psrt of the texture
        
        /// <summary>
        /// hotspot offset x and y from top left corner of 
        /// either the image - or single frame if its an animation
        /// hotspot offet is in pixels in the souce image
        /// </summary>
        protected Vector2 hotSpotOffset; // 
        //private Vector2 hotSpotOffsetScaled; // - hotspot offset in the image (adjusted for frames) for internal use only  

        /// <summary>
        /// Bounding Box rectange 
        /// x and y are offset from the HOTSPOT
        /// Warning if the hotspot is in the middle of the image/frame then x,y will be negative
        /// </summary>
        protected Rectangle bb;  
        
        /// <summary>
        /// Internal structure so one can check bounding box positions
        /// </summary>
        protected Rect4 bbTemp; // temporary for bounding box computation

        /// <summary>
        /// The waypoints for the waypoint move routines
        /// </summary>
        public WayPointList wayList { set; get; }

        private Rectangle src ; // source of image
        private Rectangle dest ; // destination of image

        int TicksToVisible = -1;
        int TicksToInvisible = -1;

        /// <summary>
        /// Default constructor
        /// </summary>
        public Sprite2()
        {
        initVars();
        }

        /// <summary>
        /// Standard Constructor
        /// </summary>
        /// <param name="visibleZ"></param>
        /// <param name="texZ"></param>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <param name="levelZ"></param>
        public Sprite2(bool visibleZ, Texture2D texZ, float x, float y, int levelZ)
        {
        initVars();
        visible = visibleZ;
        tex=texZ;

        level=levelZ;
        setWidthHeightOfTexToTex(); // sane default
        setWidthHeightToTex(); // sane default
        setBBToTexture(); // sane default again        

        setPos(x, y);
             
        }

       /// <summary>
       /// named Constructor
       /// </summary>
       /// <param name="visibleZ"></param>
       /// <param name="texZ"></param>
       /// <param name="x"></param>
       /// <param name="y"></param>
        /// <param name="levelZ"></param>       
        /// <param name="nameZ"></param>
        public Sprite2(bool visibleZ, Texture2D texZ, String nameZ, float x, float y, int levelZ)
        {
            initVars();
            visible = visibleZ;
            tex = texZ;
            name=nameZ;

            level = levelZ;
            setWidthHeightOfTexToTex(); // sane default
            setWidthHeightToTex(); // sane default
            setBBToTexture(); // sane default again        

            setPos(x, y);

        }

        /// <summary>
        /// Returns a sprite just like me at a diferent position with diferent name
        /// </summary>
        /// <returns></returns>
        public Sprite2 LikeMe(String nameZ, float x, float y)
        {
            Sprite2 retv = new Sprite2(getVisible(), getTexture(), x,y, level);
            retv.setWidthHeightOfTex(texWidth, texHeight);
            retv.setXframes(getXframes());
            retv.setYframes(getYframes());
            retv.setAnimationSequence(animationSeq, firstFrame, lastFrame, ticksBetweenFrames);
            retv.setXframe(getXframe());
            retv.setYframe(getYframe());
        return retv;
        }

        private void initVars()
        {
        visible=false;
        active=true; 

        level=-1; // -1 is the global non level

        name = "";
        tag = 0;
        kind=0;
        state = 0;

        pos.X =0; 
        pos.Y =0; 

        newPos.X=0; 
        newPos.Y=0; 

        oldPos.X=0;  
        oldPos.Y=0;  
        
        deltaSpeed.X=0; // the X, y speed (delta x, delta Y)
        deltaSpeed.Y=0; // the X, y speed (delta x, delta Y)
        moveAngle=0;
        moveSpeed=0;
        displayAngle=0;

        Xframes=1; // number of x frames 
        Yframes=1; // number of y frames
        Xframe=0; // number of the current x frame 
        Yframe=0; // number of the current y frame
        XframeWidth = 0;
        YframeHeight = 0;
        
        width=0; //
        height=0; // 

        hotSpotOffset.X=0; // hotspot offset 
        hotSpotOffset.Y=0; // hotspot offset 

        bb.X=0; // Bounding Box offset 
        bb.Y=0; // Bounding Box  offset 
        bb.Width=0; // Bounding Box width 
        bb.Height=0; // Bounding Box height 

        tex = null;
        colour = Color.White;
        flip=SpriteEffects.None;

        texWidth=0; // Width of the useful part of the texture
        texHeight=0; // heigth of the useful psrt of the texture

        TicksToVisible = -1;
        TicksToInvisible = -1;

        }

        /// <summary>
        /// gets the sprite name if one was set or ""
        /// </summary>
        /// <returns></returns>
        public string getName()
        {
            return name;
        }

        private void computeFrameParams()
        {
            XframeWidth = (int)(texWidth / Xframes); 
            YframeHeight = (int)(texHeight / Yframes);
        }

        /// <summary>
        /// Sets a source image for the sprite (usually less than the total texture) 
        /// WARNING This will alter the Xframes, Yframes
        /// </summary>
        /// <param name="r">The source image rectangle</param>
        public void setImageSource(Rectangle r)
        {
            Xframes = 0;
            Yframes = 0;
            imageSource = new Rectangle(r.X,r.Y,r.Width,r.Height);
        }

        /// <summary>
        /// set the texture - and set a default texture width and height
        /// WARNING This can alter the Xframes, Yframes
        /// </summary>
        public void setTexture(Texture2D tw)
        {
            if (tex == null)
            {
                tex = tw;
                setWidthHeightOfTexToTex();
                setWidthHeightToTex();
                computeFrameParams();
                setBBToWH();
            }
            else
            {  
                tex = tw;
            }
        }

        /// <summary>
        /// get the texturewrapper</summary>
        public Texture2D getTexture()
        {
            return tex;
        }

        /// <summary>
        /// Return a Rectangle structure which is the sprite boundaty for screen graphic purposes</summary>
        public Rectangle imageRectangle()
        {
            return new Rectangle((int)pos.X,(int)pos.Y,(int)width,(int)height);
        }

        /// <summary>
        /// Set a proposed movement position
        /// </summary>
        /// <param name="newp"> proposed movement location</param>
        public void setNewPos(Vector2 newp)
        {
            newPos.X=newp.X;
            newPos.Y=newp.Y;
        }

        /// <summary>
        /// get the proposed movent position
        /// </summary>
        /// <returns></returns>
        public Vector2 getNewPos()
        {
            return newPos;
        }

        /// <summary>
        /// Return the axis aligned bounding box at the current position 
        /// even if the display is rotated
        /// </summary>
        public Rectangle getBoundingBoxAA()
        {
            return getBoundingBoxAAPos(pos);
        }

        /// <summary>
        /// Return the mid point of the axis aligned bounding box at the current position 
        /// </summary>
        public Vector2 getBoundingBoxMiddle()
        {
            Rectangle r = getBoundingBoxAAPos(pos);
            return (new Vector2(r.X+r.Width/2.0f, r.Y+r.Height/2.0f));
        }

        /// <summary>
        /// Return the axis aligned bounding box at the proposed / new position 
        /// even if the display is rotated
        /// </summary>
        public Rectangle getBoundingBoxAAnew()
        {
            return getBoundingBoxAAPos(newPos);
        }

        /// <summary>
        /// Return the axis aligned bounding box even if the display is rotated
        /// </summary>
        /// <param name="p"> The position that the bounding box is calculated from </param>
        /// <returns></returns>
        public Rectangle getBoundingBoxAAPos(Vector2 p)
        {
            Vector2 t = new Vector2(hotSpotOffset.X*((float)width/XframeWidth),hotSpotOffset.Y*((float)height/YframeHeight)); // hotspot after scaling
            if (displayAngle + displayAngleOffset == 0)
            {
                Rectangle retv = new Rectangle((int)(p.X + bb.X - t.X), (int)(p.Y + bb.Y - t.Y), (int)bb.Width, (int)bb.Height);
                bbTemp = new Rect4(retv);
                return retv;
            }
            else
            {
                Rectangle retv = new Rectangle((int)(p.X + bb.X - t.X), (int)(p.Y + bb.Y - t.Y), (int)bb.Width, (int)bb.Height);
                bbTemp = new Rect4(retv);
                bbTemp.rotateRect(new Vector2(p.X, p.Y), displayAngle + displayAngleOffset);
                retv = bbTemp.getAABoundingRect();
                return retv;
            }
        }


        /// <summary>
        /// Return true if two sprites axis aligned bounding boxes collide at teir current locations
        /// </summary>
        public bool collision(Sprite2 s2)
        {
            return getBoundingBoxAA().Intersects(s2.getBoundingBoxAA());
        }

        /// <summary>
        /// Return true if this sprite colides with anither sprite 
        /// Uses axis aligned bounding boxes 
        /// </summary>
        public bool collisionNewPos(Sprite2 s2)
        {
            return getBoundingBoxAAnew().Intersects(s2.getBoundingBoxAA());
        }

        /// <summary>
        /// Return a rectangle that represents a collision rectange (the intersection of the two rectangles)</summary>
        public Rectangle collisionRect(Sprite2 s2)
        {
            return Rectangle.Intersect(getBoundingBoxAA(), s2.getBoundingBoxAA());
        }

        /// <summary>
        /// Return a boolean that is true if the point is inside the AA bounding box of the sprite</summary>
        public Boolean inside(float x, float y)
        {
        //  Boolean retv=true;
            Rectangle temp = getBoundingBoxAA();
            if (x < temp.Left) return false;
            if (y < temp.Top) return false;
            if (x > temp.Right) return false;
            if (y > temp.Bottom) return false;
            return true;
        }

        /// <summary>
        /// Moves the sprite by the delta x and delta y in deltaSpeed
        /// if fullmove = true then pos, newPos and oldPos are all updated and the sprite is moved
        /// if fullmove = false then only the newPos is updated and the sprite is not moved but its new location is available for 
        /// collision detection
        /// </summary>
        public void moveByDeltaXY(bool fullmove)
        {
            newPos.X = pos.X + deltaSpeed.X;
            newPos.Y = pos.Y + deltaSpeed.Y;
            if (!fullmove) return;
            oldPos.X = pos.X;
            oldPos.Y = pos.Y;

            pos.X = newPos.X;
            pos.Y = newPos.Y;
            return;
        }

        /// <summary>
        /// Moves the sprite towards the position pos
        /// </summary>
        /// <param posZ="fullmove">the position to move towards</param>
        /// <param speed="fullmove">the speed to move at </param>
        /// <param name="fullmove">true if its a full move</param>
        /// <param name="setDisplayAngle"> true if you want to orient the sprites display</param>
        /// <returns> true if we got there </returns>
        public bool moveTo(Vector2 posZ, float speed, bool fullmove, bool setDisplayAngle)
        {
            bool retv = false;
            float dist=(pos-posZ).Length();
            if (dist < 0.8) 
                return true;
            float s = speed;
            if (dist < speed) { s = dist; retv = true; }
            float moveAngle = angleTo(posZ); 
            Vector2 temp = Util.moveByAngleDist(pos, moveAngle, s);
            newPos.X = temp.X;
            newPos.Y = temp.Y;
            if (fullmove)
            {
                oldPos.X = pos.X;
                oldPos.Y = pos.Y;

                pos.X = newPos.X;
                pos.Y = newPos.Y;
            }

            if (setDisplayAngle)
            {
                float angle = Util.getAngle(pos, oldPos);
                displayAngle = angle;
            }

            return retv;
        }

        /// <summary>
        /// Moves the sprite towards the waypoint 
        /// </summary>
        /// <param speed="wayPoint">the waypoint to move to </param>
        /// <param name="fullmove">true if its a full move</param>
        /// <param name="setDisplayAngle"> true if you want to orient the sprites display</param>
        /// <returns> true if we got there </returns>
        public bool moveTo(WayPoint wayPoint, bool fullmove, bool setDisplayAngle)
        {
            return moveTo(wayPoint.pos, wayPoint.speed, fullmove, setDisplayAngle);
        }

        /// <summary>
        /// Move the sprite around the waypoint list
        /// </summary>
        /// <returns></returns>
        public bool moveWayPointList(bool fullmove, bool setDisplayAngle)
        {

            WayPoint w = wayList.currentWaypoint();
            bool rc = moveTo(w.pos, w.speed, fullmove, setDisplayAngle);
            if (rc)
            {
                bool z = wayList.nextLeg();
                if (wayList.wayFinished == 2 && !z)
                {
                    visible = false;
                    active = false;
                }
            }
            return rc;
        }

        /// <summary>
        /// Puts the sprite at the start of the waypoint list
        /// </summary>
        /// <returns></returns>
        public void moveToStartOfWayPoints()
        {
            if (wayList == null) return;
            WayPoint w = wayList.getWayPoint(0);
            setPos(w.pos);
        }

        /// <summary>
        /// Moves the sprite by the delta x and delta y in deltaSpeed
        /// if fullmove = true then pos, newPos and oldPos are all updated and the sprite is moved
        /// if fullmove = false then only the newPos is updated and the sprite is not moved but its new location is available for 
        /// collision detection
        /// </summary>
        /// <param name="fullmove"></param>
        public void moveByAngleSpeed(bool fullmove)
        {
            Vector2 temp = Util.moveByAngleDist(pos, moveAngle, moveSpeed);
            newPos.X = temp.X;
            newPos.Y = temp.Y; 
            if (!fullmove) return;
            oldPos.X = pos.X;
            oldPos.Y = pos.Y;

            pos.X = newPos.X;
            pos.Y = newPos.Y;
            return;
        }

        /// <summary>
        /// Move with screen (or world wrap)
        /// </summary>
        /// <param name="fullmove"></param>
        /// <param name="r"></param>
        public void moveByAngleSpeeedLimit(bool fullmove, Rectangle r)
        {
            Vector2 temp = Util.moveByAngleDist(pos, moveAngle, moveSpeed);
            newPos.X = temp.X;
            newPos.Y = temp.Y;

            if (newPos.X < r.X) newPos.X = newPos.X + r.Width;
            if (newPos.Y < r.Y) newPos.Y = newPos.Y + r.Height;
            if (newPos.X > r.X + r.Width) newPos.X = newPos.X - r.Width; 
            if (newPos.Y > r.Y + r.Height) newPos.Y = newPos.Y - r.Height;
            
            if (!fullmove) return;
            oldPos.X = pos.X;
            oldPos.Y = pos.Y;

            pos.X = newPos.X;
            pos.Y = newPos.Y;
            return;
        }


        /// <summary>
        /// sets the sprite location (top left of image)
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        public void setPos(float x, float y)
        {
            pos.X = x;
            pos.Y = y;
        }
        
        /// <summary>
        /// sets the sprite location (top left of image)
        /// </summary>
        /// <param name="p"></param>
        public void setPos(Vector2 p)
        {
            pos.X = p.X;
            pos.Y = p.Y;
        }

        /// <summary>
        /// sets the sprite location (top left of image)
        /// </summary>
        /// <param name="x"></param>
        public void setPosX(float x)
        {
            pos.X = x;
        }

        /// <summary>
        /// sets the sprite location (top of image) in y plane
        /// </summary>
        /// <param name="y"></param>
        public void setPosY(float y)
        {
            pos.Y = y;
        }

        /// <summary>
        /// returns the xpos of the sprite
        /// </summary>
        /// <returns></returns>
        public float getPosX()
        {
            return pos.X;
        }

        /// <summary>
        /// returns the ypos of the sprite
        /// </summary>
        /// <returns></returns>
        public float getPosY()
        {
            return pos.Y;
        }

        /// <summary>
        /// returns the position of the sprite
        /// </summary>
        /// <returns></returns>
        public Vector2 getPos()
        {
            return pos;
        }

        /// <summary>
        /// Used by the defered movement collision system 
        /// After setting newpos by some means - and checking for collisions call
        /// this routine to actually move the sprite if no collision occurs
        /// </summary>
        public void synchronisePos()
        {
            oldPos.X = pos.X;
            oldPos.Y = pos.Y;
            pos.X = newPos.X;
            pos.Y = newPos.Y; 
        }

        /// <summary>
        /// if isAmove = true then pos, newPos and oldPos are all updated and the sprite is moved
        /// if isAmove = false then only the newPos is updated and the sprite is not moved but its new location is available for 
        /// collision detection
        /// </summary>        
        public void setNewPos(float x, float y, bool isAmove)
        {
            newPos.X = x;
            newPos.Y = y;
            if (!isAmove) return;
            oldPos.X = pos.X;
            oldPos.Y = pos.Y;

            pos.X = newPos.X;
            pos.Y = newPos.Y;
        }

        /// <summary>
        /// Sets the location of pos after coillision detection has cleared newpos is ok to move to
        /// </summary>
        public void setPosToNewPos()
        {   
            oldPos.X = pos.X;
            oldPos.Y = pos.Y;
            pos.X = newPos.X;
            pos.Y = newPos.Y;
        }

        /// <summary>
        /// Set if the sprite is visible 
        /// </summary>
        /// <param name="v"></param>
        public void setVisible(bool v)
        {
            visible = v;
        }
        
        /// <summary>
        /// Um this should be obvious
        /// </summary>
        /// <returns></returns>
        public bool getVisible()
        {
            return visible;
        }

        /// <summary>
        /// Sets the blend colour for the sprite if in doubt use Color.White
        /// </summary>
        /// <param name="c"></param>
        public void setColor(Color c)
        {
            colour = c;
        }

        /// <summary>
        /// Gets the sprite blend colour
        /// </summary>
        /// <returns></returns>
        public Color getColor()
        {
            return colour;
        }

        /// <summary>
        /// gets the flip parameter 
        /// (which sets sprite effects for horizontal and vertical flipping)
        /// </summary>
        /// <returns></returns>
        public SpriteEffects getFlip()
        {
            return flip;
        }

        /// <summary>
        /// sets the flip paramentser 
        /// </summary>
        /// <param name="se"></param>
        public void setFlip(SpriteEffects se)
        {
            flip = se;
        }

        /// <summary>
        /// sets the width and height of the sprite in display pixels
        /// </summary>
        /// <param name="w"></param>
        /// <param name="h"></param>
        public void setWidthHeight(float w, float h)
        {
            width = w;
            height = h;
        }

        /// <summary>
        /// sets the width and height of the sprite to what was read in from the texture
        /// This is usefull when you want the whole image
        /// </summary>
        public void setWidthHeightToTex()
        {
            width = tex.Width;
            height = tex.Height;
        }

        /// <summary>
        /// Just set the sprite width in display pixels
        /// </summary>
        /// <param name="w"></param>
        public void setWidth(float w)
        {
            width = w;
        }

        /// <summary>
        /// just set the sprite height in display pixels
        /// </summary>
        /// <param name="h"></param>
        public void setHeight(float h)
        {
            height = h;
        }

        /// <summary>
        /// get the width in display pixels
        /// </summary>
        /// <returns></returns>
        public float getWidth()
        {
            return width;
        }

        /// <summary>
        /// get the height in display pixels
        /// </summary>
        /// <returns></returns>
        public float getHeight()
        {
            return height;
        }

        /// <summary>
        /// This sets the usefull part of the texture (which is assumed to be the top left bit)
        /// its necessary because not all textures conform to the power of 2 rule and are 
        /// upsized to a power of two
        /// </summary>
        /// <param name="w"></param>
        /// <param name="h"></param>
        public void setWidthHeightOfTex(float w, float h)
        {
            texWidth = w; // Width of the useful part of the texture
            texHeight = h; // heigth of the useful psrt of the texture
            computeFrameParams();
        }
        
        /// <summary>
        /// Just sets the active part of the texture to the whole texture
        /// </summary>
        public void setWidthHeightOfTexToTex()
        {
            setWidthHeightOfTex(tex.Width,tex.Height); // heigth of the useful psrt of the texture
        }

        /// <summary>
        /// Where we get the sprite image from not intended for external use
        /// </summary>
        public Rectangle getImageSource()
        {
            if (Xframes == 1 && Yframes == 1)
            {
                return new Rectangle(0, 0, (int)texWidth, (int)texHeight);
            }
            else
            {
                if (Xframes == 0)
                {
                    return imageSource;
                }
                else
                {
                    Rectangle r = new Rectangle();
                    r.Width = (int)XframeWidth;
                    r.Height = (int)YframeHeight;
                    r.X = Xframe * r.Width;
                    r.Y = Yframe * r.Height;
                    return r;
                }
            }
        }

        /// <summary>
        /// Where we would draw the sprite if axis aligned not intended for external use
        /// </summary>
        public Rectangle getImageDest()
        {
            return new Rectangle((int)pos.X, (int)pos.Y, (int)width, (int)height);
        }

        /// <summary>
        /// Draws the sprite if it is Visible (ie if the visible property is set)
        /// </summary>
        public override void Draw(SpriteBatch sb)
        {
            draw(sb);
        }

        /// <summary>
        /// Draws the sprite if it is Visible (ie if the visible property is set)
        /// </summary>
        public void draw(SpriteBatch sb)
        {
            if (visible)
            {
                  src = getImageSource();
                  dest = getImageDest();
                  Vector2 rotateImage; // = getRotateImage();
                  rotateImage.X = hotSpotOffset.X;
                  rotateImage.Y = hotSpotOffset.Y;
                  sb.Draw(tex, dest,src, getColor(), displayAngle+displayAngleOffset, rotateImage, flip, 0.5f);
            }
        }

        /// <summary>
        /// Gets the point about which to rotate the image in Image co-ordinates
        /// </summary>
        /// <returns></returns>
        public Vector2 getRotateImage()
        {
            Vector2 retv;
            if (Xframes==1 && Yframes==1)
            {
                retv.X = hotSpotOffset.X;
                retv.Y = hotSpotOffset.Y;
            }
            else
            {
                retv.X = hotSpotOffset.X + (XframeWidth * Xframe);
                retv.Y = hotSpotOffset.Y + (YframeHeight * Yframe);
            }
            return retv;
        }

        /// <summary>
        /// Sets the bounding box relative to the hotspot (or position)
        /// if the hotspot is in the middle of the source image there is a fair chance
        /// that bb.X and bb.Y will be negative
        /// </summary>
        /// <param name="bbXoffset"></param>
        /// <param name="bbYoffset"></param>
        /// <param name="bbWidthZ"></param>
        /// <param name="bbHeightZ"></param>
        public void setBB(float bbXoffset, float bbYoffset, float bbWidthZ, float bbHeightZ)
        {
            bb.X = Convert.ToInt32(bbXoffset);
            bb.Y = Convert.ToInt32(bbYoffset);
            bb.Width = Convert.ToInt32(bbWidthZ); // Bounding Box width 
            bb.Height = Convert.ToInt32(bbHeightZ); // Bounding Box height 
        }

        /// <summary>
        /// lol for basic sprites set the BB to the texture with and height
        /// </summary>
        public void setBBToTexture()
        {
            bb.X = 0;
            bb.Y = 0;
            bb.Width = tex.Width; // Bounding Box width 
            bb.Height = tex.Height; // Bounding Box height 
        }

        /// <summary>
        /// lol for less basic sprites set the BB to the texture active width and active height
        /// </summary>
        public void setBBToTextureActive()
        {
            bb.X = 0;
            bb.Y = 0;
            bb.Width = tex.Width; // Bounding Box width 
            bb.Height = tex.Height; // Bounding Box height 
        }


        /// <summary>
        /// set the bounding box to the width and height of the sprite
        /// typically this is a bounding box that follows the image boundary
        /// with a hotspot in the image top left corner
        /// </summary>
        public void setBBToWH()
        {
            bb.X = 0;
            bb.Y = 0;
            bb.Width = (int)width; // Bounding Box width 
            bb.Height = (int)height; // Bounding Box height
        }

        /// <summary>
        /// set the bounding box to the width and height of A single frame
        /// typically this is a bounding box that follows the image boundary
        /// with a hotspot in the image top left corner
        /// </summary>
        public void setBBToFrame()
        {
            bb.X = 0;
            bb.Y = 0;
            bb.Width = (int)(texWidth/Xframes); // Bounding Box width 
            bb.Height = (int)(texWidth/Yframes); // Bounding Box height
        }

        /// <summary>
        /// Sets the bounding box to a fraction of the normal width and height 
        /// eg setBBToFraction(0.6) would creat a small bounding box whose dimensions are 
        /// 0.6 of the full sprite dimensions
        /// The bounding box is centered at the hotspot - unless the hotspot is in pos 0,0
        /// in which case it is suitably offset
        /// </summary>
        public void setBBToFraction(float f)
        {
            bb.Width = Convert.ToInt32(width*f); // Bounding Box width 
            bb.Height = Convert.ToInt32(height*f); // Bounding Box height           
            bb.X = Convert.ToInt32(width*(1-f)/2);
            bb.Y = Convert.ToInt32(height*(1-f)/2);
            //}
            //else
            //{
            //    // set bb centered on hot spot
            //    bb.X = Convert.ToInt32(-bb.Width/ 2.0);
            //    bb.Y = Convert.ToInt32(-bb.Height/ 2.0);
            //}
        }

        /// <summary>
        /// Get the bouding rectange in screen co ordinates - relative to the sprite pos
        /// </summary>
        /// <returns></returns>
        public Rectangle getBB()
        {
            return bb;
        }

  
        /// <summary>
        /// Set the hotspot offset 
        /// Note that this is in image pixels  
        /// </summary>
        /// <param name="offset"></param>
        public void  setHSoffset(Vector2 offset)
        {
        hotSpotOffset.X=offset.X;
        hotSpotOffset.Y=offset.Y;
        //computeHotSpotOS();
        }

        /// <summary>
        /// set the Hotspot offset
        /// </summary>
        /// <returns></returns>
        public Vector2 getHSOffset()
        {
            return hotSpotOffset;
        }

        ///// <summary>
        ///// set the Hotspot offset
        ///// </summary>
        ///// <returns></returns>
        //public Vector2 getHSScreen()
        //{
        //    Vector2 retv = new Vector2(hotSpotOffset.X+pos.X,hotSpotOffset.Y+pos.Y);
        //    return retv;
        //}

        /// <summary>
        /// draws a bounding box
        /// </summary>
        /// <param name="sb"></param>
        /// <param name="c"></param>
        public virtual void drawBB(SpriteBatch sb, Color c) // 
        {
            Rectangle bb = getBoundingBoxAA();
            LineBatch.drawLineRectangle(sb, bb, c);
        }

        /// <summary>
        /// Draws the hotspot/position of the sprite
        /// </summary>
        /// <param name="sb"></param>
        /// <param name="c"></param>
        public void drawHS(SpriteBatch sb, Color c) // 
        {
            //Vector2 rotateImage = getRotateImage();
            LineBatch.drawCross(sb, pos.X, pos.Y, 3, c, c);
        }

        /// <summary>
        /// draw bounding box and hotspot
        /// </summary>
        /// <param name="sb"></param>
        /// <param name="colorBB"></param>
        /// <param name="colorHS"></param>
        public void drawInfo(SpriteBatch sb, Color colorBB, Color colorHS)  
        {
            drawBB(sb,colorBB);
            drawHS(sb, colorHS);
        }

        /// <summary>
        /// For debugging only to make sure rotations are where they are expected to be
        /// </summary>
        /// <param name="sb"></param>
        /// <param name="c"></param>
        public void drawRect4(SpriteBatch sb, Color c)
        {
            LineBatch.drawRect4(sb, bbTemp, c);
        }

        /// <summary>
        /// Set a speed vector for the deltax/deltay move system
        /// </summary>
        /// <param name="ds"></param>
        public void setDeltaSpeed(Vector2 ds)
        {
            deltaSpeed=ds; // the X, y speed (delta x, delta Y)
        }

        /// <summary>
        /// get the speed deltas for the deltax deltay move system
        /// </summary>
        /// <returns></returns>
        public Vector2 getDeltaSpeed()
        {
            return deltaSpeed;
        }

        /// <summary>
        /// Get the current movemnet angle for the angle / speed move system in radians
        /// </summary>
        /// <returns></returns>
        public float getMoveAngle()    // in radians
        {
            return moveAngle;
        }

        /// <summary>
        /// Get the current movemnet angle for the angle / speed move system
        /// </summary>
        /// <param name="m"></param>
        public void setMoveAngle(float m)    // in radians
        {
            moveAngle=m;
        }

        /// <summary>
        /// Get the current movemnet speed for the angle / speed move system
        /// </summary>
        /// <returns></returns>
        public float getMoveSpeed()
        {
            return moveSpeed;
        }

        /// <summary>
        /// Set the current movemnet speed for the angle / speed move system
        /// </summary>
        /// <param name="m"></param>
        public void setMoveSpeed(float m)
        {
            moveSpeed=m;
        }

        /// <summary>
        /// get display angle in radians
        /// </summary>
        /// <returns></returns>
        public float getDisplayAngle() // in radians
        {
            return displayAngle;
        }

        /// <summary>
        /// set display angle in radians
        /// </summary>
        /// <returns></returns>
        public void setDisplayAngle(float d) // in radians
        {
            displayAngle=d;
        }

        /// <summary>
        /// set the display angle offset - which is the angle added to the displayAngle to make the sprite face in direction 0
        /// </summary>
        /// <param name="d"></param>
        public void setDisplayAngleOffset(float d)
        {
            displayAngleOffset = d;
        }

        /// <summary>
        /// get the display angle offset
        /// </summary>
        /// <returns></returns>
        public float getDisplayAngleOffset()
        {
            return displayAngleOffset;
        }


        /// <summary>
        /// Set the number of horizontal frames of animation
        /// </summary>
        /// <param name="f"></param>
        public void setXframes(int f) // 
        {
            Xframes = f;
            computeFrameParams();
        }

        /// <summary>
        /// Set the number of vertical frames of animation
        /// </summary>
        /// <param name="f"></param>
        public void setYframes(int f) // 
        {
            Yframes = f;
            computeFrameParams();
        }

        /// <summary>
        /// get the number of vertical frames of animation
        /// </summary>
        /// <returns></returns>
        public int getYframes() // 
        {
            return Yframes;
        }
        
        /// <summary>
        /// set the number of vertical frames of animation
        /// </summary>
        /// <returns></returns>
        public int getXframes() // 
        {
            return Xframes;
        }

        /// <summary>
        /// get the current horizontal frame
        /// </summary>
        /// <returns></returns>
        public int getXframe() // 
        {
            return Xframe;
        }

        /// <summary>
        /// get the current vertical frame
        /// </summary>
        /// <returns></returns>
        public int getYframe() // 
        {
            return Yframe;
        }
        
        /// <summary>
        /// Get the current frame number which is an index into the 
        /// animation frame sequence data updated by setAnimationSequence 
        /// </summary>
        /// <returns></returns>
        public int getFrame() // 
        {
            return frame;
        }

        /// <summary>
        /// set the current vertical frame
        /// </summary>
        /// <param name="f"></param>
        public void setYframe(int f) // 
        {
            Yframe = f;
        }

        /// <summary>
        /// Set the current horizontal frame
        /// </summary>
        /// <param name="f"></param>
        public void setXframe(int f) // 
        {
            Xframe = f;
        }

        /// <summary>
        /// Set the current frame number which is an index into the 
        /// animation frame sequence data updated by setAnimationSequence 
        /// </summary>
        /// <param name="f"></param>
        public void setFrame(int f) // 
        {
            frame = f;
        }

        /// <summary>
        /// Set an animation sequenece
        /// </summary>
        /// <param name="animSeq"></param>
        /// <param name="firstFrameZ"></param>
        /// <param name="lastFrameZ"></param>
        /// <param name="ticksBetweenFramesZ"></param>
        public void setAnimationSequence(Vector2[] animSeq, int firstFrameZ, int lastFrameZ, int ticksBetweenFramesZ) // the frame sequence
        {

            animationSeq = animSeq;
            firstFrame = firstFrameZ;
            lastFrame = lastFrameZ;
            ticksBetweenFrames = ticksBetweenFramesZ;
        }

        /// <summary>
        /// Upadate the animation sequence
        /// This routine is usuall run in the update routine
        /// </summary>
        public void animationTick()
        {
            if (animationSeq == null) return;
            ticks++;
            if (ticksBetweenFrames != 0)
            if (ticks % ticksBetweenFrames == 0)
            {
                frame = frame + 1;
                if (frame > lastFrame) 
                {
                // 0=loop
                // 1=set sprite invisible
                // 2=set sprite inactive and invisible
                if (animFinished==0) frame = firstFrame;
                if (animFinished > 0)
                {
                    visible = false;
                    frame = firstFrame;
                }
                if (animFinished == 2)
                    {
                        active = false;
                        visible=false;
                        frame = firstFrame;
                    }

                }
                Xframe = (int)animationSeq[frame].X;
                Yframe = (int)animationSeq[frame].Y;
            }
        }

        /// <summary>
        /// What to do when the animation is finished
        /// 0=loop
        /// 1=set sprite invisible
        /// 2=set sprite inactive and invisible
        /// </summary>
        /// <param name="whatToDo"></param>
        public void setAnimFinished(int whatToDo)
        {
            animFinished = whatToDo;
        }

        /// <summary>
        /// Set the start parameters for the animation sequence
        /// </summary>
        public void animationStart()
        {
            frame = firstFrame;
            ticks = 0;
            Xframe = (int)animationSeq[frame].X;
            Yframe = (int)animationSeq[frame].Y;
        }

        /// <summary>
        /// Set the start parameters for the animation sequence allowing for some additional information
        /// </summary>
        /// <param name="ticksZ"></param>
        /// <param name="frameZ"></param>
        public void animationStart(int ticksZ, int frameZ)
        {
            frame = frameZ;
            ticks = ticksZ;
            Xframe = (int)animationSeq[frame].X;
            Yframe = (int)animationSeq[frame].Y;
        }

        /// <summary>
        /// Distance to another sprite
        /// </summary>
        /// <param name="sprite"></param>
        /// <returns></returns>
        public float distanceTo(Sprite2 sprite)
        {
            return distanceTo(sprite.getPos());
        }

        /// <summary>
        /// Distance to an arbitary point
        /// </summary>
        /// <param name="point"></param>
        /// <returns></returns>
        public float distanceTo(Vector2 point)
        {
            return (pos - point).Length();
        }

        /// <summary>
        /// Aligns the display angle to the sprites current movement angle based on oldpos - 
        /// only works if the spriye is actually moving
        /// </summary>
        public void alignDisplayAngle()
        {
            if (oldPos.X == pos.X && oldPos.Y == pos.Y) return;
            setDisplayAngle((float)(angleTo(oldPos)+Math.PI));
        }

        /// <summary>
        /// computes the angle to another sprite
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        public float angleTo(Sprite2 s)
        {
            return angleTo(s.getPos());
        }

        /// <summary>
        /// computes the angle to an arbitary point
        /// </summary>
        /// <param name="point"></param>
        /// <returns></returns>
        public float angleTo(Vector2 point)
        {
            return Util.getAngle(point,pos);
        }

        /// <summary>
        /// get the active flag
        /// </summary>
        /// <returns></returns>
        public bool getActive() { return active; }

        /// <summary>
        /// set the active flag
        /// </summary>
        /// <param name="activeZ"></param>
        public void setActive(bool activeZ) { active=activeZ; }

        /// <summary>
        /// sets the number if ticks till the sprite becomes visible
        /// </summary>
        /// <param name="ticks"></param>
        public void setTicksToVisible(int ticks)
        {
        TicksToVisible=ticks;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="ticks"></param>
        public void setTicksToInvisible(int ticks)
        {
        TicksToInvisible = ticks;
        }

        /// <summary>
        /// Tick the visible / invisible ticker
        /// </summary>
        public virtual void tick()
        {
            if (TicksToVisible > 0)
            {
                TicksToVisible--;
                if (TicksToVisible == 0) setVisible(true);
            }

            if (TicksToInvisible > 0)
            {
                TicksToInvisible--;
                if (TicksToInvisible == 0) setVisible(false);
            }


        }

    }

}
